package br.ufrn.dimap;

import java.util.ArrayList;

public class AnalisadorSintatico {

	private ArrayList<Lexema> list_lex;
	private Token token;
	
	public AnalisadorSintatico(ArrayList<Lexema> lexemas){
		this.list_lex = lexemas;
		programa();
	}
	
	private void programa(){
		
		if(removeToken() == Token.T_PROGRAMA){
			while(getToken() != Token.T_FIM_PROGRAMA && !list_lex.isEmpty()){
				inst();
			}
			
			if(removeToken() != Token.T_FIM_PROGRAMA){
				erro();
			}		
		}else{
			erro();
		}
		
	}
	
	private void inst(){
		
		switch(getToken()){
			case T_VAR:
				var();
				break;
			case T_CONST:
				var();
				break;
			case T_TIPO:
				tipoRegistro();
				break;
			case T_FUNCAO:
				funcao();
				break;
			case T_PROCEDIMENTO:
				
				break;
			case T_IDENTIFICADOR:
				
				break;
		}
		
		if(removeToken() != Token.T_PONTO_E_VIRGULA){
			erro();
		}
	}
	
	private void var(){
		removeToken();
		
		if(removeToken() != Token.T_IDENTIFICADOR){
			erro();
		}
		if(removeToken() != Token.T_DOIS_PONTOS){
			erro();
		}
		
		tipo();
		
		if(getToken() == Token.T_ATRIBUICAO){
			removeToken();
			expressao();
		}
		
		if(removeToken() != Token.T_PONTO_E_VIRGULA){
			erro();
		}
		
	}
	
	private void tipo(){
		Token t = getToken();
		if(t == Token.T_TIPO_INTEIRO || t == Token.T_TIPO_REAL || t == Token.T_TIPO_CARACTERE ||
		   t == Token.T_TIPO_CARACTERE || t == Token.T_TIPO_BOOLEANO){
			
			removeToken();
		}
		else if( t == Token.T_TIPO_ARRANJO){
			arranjo();
		}
	}
	
	private void arranjo(){
		removeToken();
		
		if(removeToken() == Token.T_DE){
			tamanhoArranjo();
			tipo();
		}else{
			erro();
		}
	}
	
	private void tamanhoArranjo(){
		if(removeToken() == Token.T_TIPO_INTEIRO){
			if(getToken() == Token.T_POR){
				removeToken();
				
				if(removeToken() != Token.T_TIPO_INTEIRO){
					erro();
				}
			}
		}else{
			erro();
		}
	}
	
	private void tipoRegistro(){
		removeToken();
		
		if(removeToken() == Token.T_IDENTIFICADOR){
			if(removeToken() == Token.T_ESTRUTURA){
				var();
				
				while(getToken() == Token.T_FIM_TIPO || !list_lex.isEmpty()){
					var();
				}
				
				if(removeToken() != Token.T_FIM_TIPO){
					erro();
				}				
			}else{
				erro();
			}
		}else{
			erro();
		}
	}
	
	private void funcao(){
		removeToken();
		
		if(removeToken() == Token.T_IDENTIFICADOR){
			if(removeToken() != Token.T_SEPARADOR_ABRE_PARENTESES){
				erro();
			}
			
			listaParametros();
			
			if(removeToken() != Token.T_SEPARADOR_FECHA_PARENTESES){
				erro();
			}
			
			if(removeToken() != Token.T_DOIS_PONTOS){
				erro();
			}
			
			tipo();
			instrucao();
			
			if(removeToken() != Token.T_RETORNO){
				erro();
			}
			
			expressao();
			
			if(removeToken() != Token.T_PONTO_E_VIRGULA){
				erro();
			}

		}else{
			erro();
		}
	}
	
	private void listaParametros(){
		while(getToken() == Token.T_IDENTIFICADOR){
			removeToken();
			
			if(removeToken() != Token.T_DOIS_PONTOS){
				erro();
			}
			
			tipo();
			
			if(removeToken() != Token.T_PONTO_E_VIRGULA){
				erro();
			}
		}
	}
	
	private void instrucao(){
		
		switch(getToken()){
			case T_VAR:
				var();
				break;
			case T_IDENTIFICADOR:
				atribuicao();
				break;
			case T_SE:
				se();
				break;
			case T_ENQUANTO:
				enquanto();
				break;
			case T_PARA:
				para();
				break;
			case T_CASO:
				caso();
				break;
		}
	}
	
	private void atribuicao(){
		removeToken();
		
		if(removeToken() != Token.T_ATRIBUICAO){
			erro();
		}
		
		expressao();
		
		if(removeToken() != Token.T_PONTO_E_VIRGULA){
			erro();
		}
	}

	private void se(){
		removeToken();
		
		condicao();
		
		if(removeToken() != Token.T_ENTAO){
			erro();
		}
		
		while(getToken() != Token.T_FIM_SE && !list_lex.isEmpty()){
			
			if(getToken() == Token.T_SENAO){
				removeToken();
				do{
					inst();
				}while(getToken() != Token.T_SENAO);

			}else{
				inst();
			}			
		}
		removeToken();
	}
	
	private void enquanto(){
		removeToken();
		
		condicao();
		
		if(removeToken() != Token.T_FACA){
			erro();
		}
		
		while(getToken() != Token.T_FIM_ENQUANTO && !list_lex.isEmpty()){
			inst();
		}
		
		removeToken();
	}

	private void para(){
		removeToken();
		
		if(removeToken() != Token.T_DE){
			erro();
		}
		
		if(removeToken() != Token.T_TIPO_INTEIRO){
			erro();
		}
		
		if(removeToken() != Token.T_ATE){
			erro();
		}
		
		if(removeToken() != Token.T_TIPO_INTEIRO){
			erro();
		}
		
		if(getToken() == Token.T_COM){
			removeToken();
			
			if(removeToken() != Token.T_PASSO){
				erro();
			}
			
			if(removeToken() != Token.T_TIPO_INTEIRO){
				erro();
			}
		}
		
		if(removeToken() != Token.T_FACA){
			erro();
		}
		
		while(getToken() != Token.T_FIM_PARA && !list_lex.isEmpty()){
			inst();
		}
		
		removeToken();
	}

	private void caso(){
		removeToken();
		
		if(removeToken() != Token.T_IDENTIFICADOR){
			erro();
		}
		
		if(removeToken() != Token.T_SEJA){
			erro();
		}
		
		while(getToken() != Token.T_FIM_CASO && !list_lex.isEmpty()){
			
			if(getToken() == Token.T_IGUAL){
				removeToken();
				
				if(removeToken() != Token.T_A){
					erro();
				}
				
				while(getToken() != Token.T_IGUAL && getToken() != Token.T_SENAO && getToken() != Token.T_FIM_CASO && !list_lex.isEmpty()){
					inst();
				}
				
			}
			else if(getToken() == Token.T_SENAO){
				removeToken();
				
				while(getToken() != Token.T_SENAO && getToken() != Token.T_FIM_CASO && !list_lex.isEmpty()){
					inst();
				}
			}
		}		
		removeToken();
		
	}
	
	private void condicao(){
		
	}
	
	private void expressao(){
		
	}
	
	private void erro(){
		System.out.println("Erro!!!!!!!!");
	}
	
	private Token removeToken(){
		if(list_lex.isEmpty()){
			erro();
		}		
		return list_lex.remove(0).getToken();
		
	}
	
	private Token getToken(){
		if(!list_lex.isEmpty()){
			return list_lex.get(0).getToken();
		}else{
			return null;
		}
	}
}
